/******************************************************************************
	This file is a part of the Snapshot Bioinformatics Project

	Copyright (C) 2012-2013 Jarom Schow

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include "SnapshotTreeModel.h"

#include <QtCore/QSettings>

#include "SnapshotTree.h"

/**
**/
SnapshotTreeModel::SnapshotTreeModel() : m_tree( NULL )
{
}

/**
**/
SnapshotTreeModel::~SnapshotTreeModel()
{
}

/**
**/
void SnapshotTreeModel::setTree( SnapshotTree *tree )
{
	m_tree = tree;
	connect( m_tree, SIGNAL(coverageChanged()), this, SLOT(updateCoverage()) );
	connect( m_tree, SIGNAL(rootAdded(SnapshotNode*)), this, SLOT(rootAdded()) );
	connect( m_tree, SIGNAL(cleared()), this, SLOT(rootsCleared()) );
}

/**
**/
QModelIndex SnapshotTreeModel::index( int row, int column, const QModelIndex &parent ) const
{
	if( !m_tree || column < 0 || column > 1 )
		return QModelIndex();

	if( parent.isValid() ){
		SnapshotNode	*parentNode = reinterpret_cast<SnapshotNode*>( parent.internalPointer() );

		if( !parentNode )
			return QModelIndex();

		if( row < 0 || row >= parentNode->getNumChildren() )
			return QModelIndex();

		return createIndex( row, column, parentNode->getChild( row ) );
	}
	
	SnapshotNode	*node = m_tree->getRoot( row );

	if( node )
		return createIndex( row, column, node );

	return QModelIndex();
}

/**
**/
QModelIndex SnapshotTreeModel::parent( const QModelIndex &index ) const
{
	if( !index.isValid() )
		return QModelIndex();

	SnapshotNode	*node = reinterpret_cast<SnapshotNode*>( index.internalPointer() );

	if( !node )
		return QModelIndex();

	SnapshotNode	*parent = node->getParent();

	if( parent ){
		int				row = 0;
		SnapshotNode	*grandParent = parent->getParent();

		if( grandParent )
			row = grandParent->indexOf( parent );
		else
			row = m_tree->indexOf( parent );

		if( row >= 0 )
			return createIndex( row, 0, parent );
	}

	return QModelIndex();
}

/**
**/
int SnapshotTreeModel::rowCount( const QModelIndex &parent ) const
{
	if( parent.isValid() ){
		SnapshotNode	*node = reinterpret_cast<SnapshotNode*>( parent.internalPointer() );

		if( !node )
			return 0;

		return node->getNumChildren();
	}

	if( m_tree )
		return m_tree->getNumRoots();

	return 0;
}

/**
**/
int SnapshotTreeModel::columnCount( const QModelIndex & parent ) const
{
	return 2;
}

/**
**/
QVariant SnapshotTreeModel::data( const QModelIndex &index, int role ) const
{
	if( role != Qt::DisplayRole || !index.isValid() )
		return QVariant();

	SnapshotNode	*node = reinterpret_cast<SnapshotNode*>( index.internalPointer() );

	if( node ){
		if( index.column() == 0 ) {
			QString	scientificName = node->getScientificName();
			QString	commonName = node->getCommonName();

			if( scientificName.isEmpty() )
				scientificName = QString::number( node->getTaxonId() ); //"unknown";

			if( commonName.isEmpty() )
				return scientificName;

			return QString( "%1 (%2)" ).arg( scientificName ).arg( commonName );
		}
		else if( index.column() == 1 )
			return QString( "%1%" ).arg( node->getCoverage() * 100.0f, 3, 'f', 0 );
	}

	return QVariant();
}

/**
**/
QVariant SnapshotTreeModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if( role != Qt::DisplayRole )
		return QVariant();

	if( section == 0 )
		return tr( "Taxa" );
	else if( section == 1 )
		return tr( "Coverage" );

	return QVariant();
}

/**
**/
void SnapshotTreeModel::rootAdded()
{
	if( !m_tree )
		return;

	int	idx = m_tree->getNumRoots() - 1;

	beginInsertRows( QModelIndex(), idx, idx );
	endInsertRows();
}

/**
**/
void SnapshotTreeModel::rootsCleared()
{
	beginResetModel();
	// May have to change how this is done since the data should not be changed before beginResetModel() is called.
	endResetModel();
}

/**
**/
void SnapshotTreeModel::updateCoverage()
{
	if( !m_tree )
		return;

	int	numRoots = m_tree->getNumRoots();

	if( numRoots < 1 )
		return;
	
	QModelIndex	indexTop = createIndex( 0, 1, m_tree->getRoot( 0 ) );
	QModelIndex	indexBottom = createIndex( numRoots - 1, 1, m_tree->getRoot( numRoots - 1 ) );

	emit dataChanged( indexTop, indexBottom );
	
	QListIterator<SnapshotNode*>	childIt( m_tree->getRootIterator() );

	while( childIt.hasNext() )
		updateCoverage( childIt.next() );
}

/**
**/
void SnapshotTreeModel::updateCoverage( SnapshotNode *node )
{
	if( !node )
		return;

	int	numChildren = node->getNumChildren();

	if( numChildren < 1 )
		return;
	
	QModelIndex	indexTop = createIndex( 0, 1, node->getChild( 0 ) );
	QModelIndex	indexBottom = createIndex( numChildren - 1, 1, node->getChild( numChildren - 1 ) );

	emit dataChanged( indexTop, indexBottom );
	
	QListIterator<SnapshotNode*>	childIt( node->getChildIterator() );

	while( childIt.hasNext() )
		updateCoverage( childIt.next() );
}

/**
**/
SnapshotTreeProxyModel::SnapshotTreeProxyModel() : m_tree( NULL )
{
	m_sourceModel = new SnapshotTreeModel;
	setSourceModel( m_sourceModel );
}

/**
**/
SnapshotTreeProxyModel::~SnapshotTreeProxyModel()
{
}

/**
**/
void SnapshotTreeProxyModel::setTree( SnapshotTree *tree )
{
	m_tree = tree;
	connect( m_tree, SIGNAL(visibilityChanged()), this, SLOT(updateVisibility()) );

	m_sourceModel->setTree( tree );
	invalidate();
}

/**
**/
bool SnapshotTreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
{
	if( !m_tree )
		return false;

	if( !sourceParent.isValid() )
		return true;

	SnapshotNode	*node = reinterpret_cast<SnapshotNode*>( sourceParent.internalPointer() );

	if( !node )
		return false;

	SnapshotNode	*child = node->getChild( sourceRow );

	if( !child )
		return false;

	return child->isVisible();
}

/**
**/
void SnapshotTreeProxyModel::updateVisibility()
{
	invalidateFilter();
}
